package main.java.FSMDE.views;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import main.java.FSMDE.controllers.TransitionController;
import main.java.FSMDE.infrastructure.visual.ComponentTreeNode;
import main.java.FSMDE.infrastructure.visual.InterfaceTreeNode;
import main.java.FSMDE.models.ComplexComponent;
import main.java.FSMDE.models.Component;
import main.java.FSMDE.models.Interface;
import main.java.FSMDE.models.Operations;
import main.java.FSMDE.models.TransitionType;

import com.jgoodies.forms.factories.CC;
import com.jgoodies.forms.layout.FormLayout;


public class TransitionView implements ITransitionView {

	private static String CREATION_TITLE = "Transition Creation";
	private static String UPDATE_TITLE = "Transition Update";

	private static String noneInterface = "None";

	private JFrame frame1;

	private JLabel transitionNameText;

	private JTextField transitionName;
	private JTextField functionName;

	private JLabel interfaceNameText;
	private JLabel transitionTypeText;
	private JLabel interface1Text;
	private JLabel interface2Text;
	private JLabel functionNameText;
	private JLabel controlText;
	private JLabel controlInterfaceText;
	private JLabel controlComponentText;

	@SuppressWarnings("rawtypes")
	private JComboBox transitionTypeComboBox;
	@SuppressWarnings("rawtypes")
	private JComboBox sourceInterfaceCombo;
	@SuppressWarnings("rawtypes")
	private JComboBox destinationInterfaceCombo;
	@SuppressWarnings("rawtypes")
	private JComboBox controlComponentCombo;

	private DefaultTreeModel interfaceTreeModel;
	private JTree interfaceTree;
	private JScrollPane treeContainer;

	private JPanel functionalPanel;
	private JPanel controlPanel;

	private JButton createButton;
	private JButton cancelButton;

	private JButton buttonAdd;
	private JButton buttonRemove;

	private TransitionController transitionController;

	protected JScrollPane functionalTableContainer;

	// REMOVE AND REPLACE BY private Iterable<Interface> interfaces; |
	Set<Interface> interfaces = new HashSet<Interface>();

	private Iterable<Interface> allInterfaces;

	private DefaultMutableTreeNode componentRoot;

	private Operations operation;

	public TransitionView() {
		initComponents();
		createButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				createTransition();
			}
		});

		cancelButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				cancelAction();
			}
		});

		transitionTypeComboBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {

				if (transitionTypeComboBox.getSelectedItem() == TransitionType.Functional) {
					functionalPanel.setVisible(true);
					controlPanel.setVisible(false);
				} else {
					controlPanel.setVisible(true);
					functionalPanel.setVisible(false);
				}
			}
		});

		frame1.setTitle(CREATION_TITLE);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void initComponents() {
		frame1 = new JFrame();
		frame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		frame1.setUndecorated(true);
		frame1.getRootPane().setWindowDecorationStyle(
				JRootPane.INFORMATION_DIALOG);
		frame1.setSize(528, 250);
		transitionNameText = new JLabel();
		transitionName = new JTextField();
		functionName = new JTextField();
		interfaceNameText = new JLabel();
		functionNameText = new JLabel();
		controlInterfaceText = new JLabel();
		controlComponentText = new JLabel();
		controlText = new JLabel();
		transitionTypeText = new JLabel();
		transitionTypeComboBox = new JComboBox(TransitionType.values());
		interface1Text = new JLabel();
		sourceInterfaceCombo = new JComboBox();
		interface2Text = new JLabel();
		destinationInterfaceCombo = new JComboBox();
		controlComponentCombo = new JComboBox();
		functionalPanel = new JPanel();
		controlPanel = new JPanel();
		createButton = new JButton();
		cancelButton = new JButton();

		buttonAdd = new JButton();
		buttonRemove = new JButton();

		functionalTableContainer = new JScrollPane();

		interfaceTree = new JTree();
		componentRoot = new DefaultMutableTreeNode("Components");
		interfaceTreeModel = new DefaultTreeModel(componentRoot);
		interfaceTree.setModel(interfaceTreeModel);
		treeContainer = new JScrollPane(interfaceTree);

		// buttonAdd.addActionListener(new ButtonAddActionListener());
		// buttonRemove.addActionListener(new ButtonRemoveActionListener());

		sourceInterfaceCombo.addItem(noneInterface);

		destinationInterfaceCombo.addItem(noneInterface);

		// ======== frame1 ========
		{
			frame1.setTitle("Transition Creation");
			Container frame1ContentPane = frame1.getContentPane();
			frame1ContentPane.setLayout(new FormLayout(
					"70*(default, $lcgap), default",
					"73*(default, $lgap), default"));
			frame1ContentPane.setPreferredSize(new Dimension(528, 411));
			// ---- Transition name ----
			transitionNameText.setText("Name: ");
			transitionNameText.setLabelFor(transitionName);
			frame1ContentPane.add(transitionNameText, CC.xy(5, 3));
			frame1ContentPane.add(transitionName, CC.xywh(9, 3, 20, 1));

			// ---- Transition type ----
			transitionTypeText.setText("Type: ");
			transitionTypeText.setLabelFor(transitionTypeComboBox);
			frame1ContentPane.add(transitionTypeText, CC.xy(5, 7));
			frame1ContentPane.add(transitionTypeComboBox, CC.xy(9, 7));

			// ---- Interface label ----
			interfaceNameText.setText("Interfaces:");
			frame1ContentPane.add(interfaceNameText, CC.xy(5, 9));

			// ---- Interface 1 ----
			interface1Text.setText("Source: ");
			interface1Text.setLabelFor(sourceInterfaceCombo);
			frame1ContentPane.add(interface1Text, CC.xy(5, 11));
			frame1ContentPane.add(sourceInterfaceCombo, CC.xywh(9, 11, 28, 1));
			// sourceInterfaceCombo.setPreferredSize(new Dimension(120,25));

			// ---- Interface 2 ----
			interface2Text.setText("Destination: ");
			interface2Text.setLabelFor(destinationInterfaceCombo);
			frame1ContentPane.add(interface2Text, CC.xy(43, 11));
			frame1ContentPane.add(destinationInterfaceCombo,
					CC.xywh(48, 11, 56, 1));
			// destinationInterfaceCombo.setPreferredSize(new
			// Dimension(120,25));

			// ---- buttonAdd ----
			buttonAdd.setText("Add");

			// ---- buttonRemove ----
			buttonRemove.setText("Remove");

			// ---- cancelButton ----
			cancelButton.setText("Cancel");
			frame1ContentPane.add(cancelButton, CC.xywh(70, 110, 36, 10));

			// ---- createButton ----
			createButton.setText("Finish");
			frame1ContentPane.add(createButton, CC.xywh(70, 122, 36, 10));

			// ======== Optional section ========
			{
				// functionalPanel.setLayout(new BorderLayout());

				// Functional
				functionalPanel.setLayout(new FormLayout(
						"100*(default, $lcgap), default",
						"73*(default, $lgap), default"));
				// functionalPanel.setLayout(new BorderLayout());
				functionNameText.setText("Function name:");
				functionNameText.setLabelFor(functionName);
				functionalPanel.add(functionNameText, CC.xy(1, 1));
				functionalPanel.add(functionName, CC.xywh(9, 1, 41, 1));
				// functionalPanel.add(functionNameText,
				// BorderLayout.PAGE_START);

				// Control
				controlPanel.setLayout(new FormLayout(
						"74*(default, $lcgap), default",
						"73*(default, $lgap), default"));
				controlText.setText("Component Trigger");
				// functionNameText.setLabelFor(functionName);
				controlInterfaceText.setText("Interface:");
				controlInterfaceText.setLabelFor(treeContainer);
				controlComponentText.setText("Component:");
				controlComponentText.setLabelFor(controlComponentCombo);
				controlPanel.add(controlText, CC.xy(1, 1));
				controlPanel.add(controlInterfaceText, CC.xy(1, 3));
				controlPanel.add(treeContainer, CC.xywh(5, 3, 80, 80));
				controlPanel.add(controlComponentText, CC.xy(9, 3));
				controlPanel.add(controlComponentCombo, CC.xy(13, 3));
				controlComponentText.setVisible(false);
				controlComponentCombo.setVisible(false);
				// functionalTableContainer.getViewport().add(table);
				// functionalPanel.add(functionalTableContainer);
			}
			frame1ContentPane.add(functionalPanel, CC.xywh(5, 26, 80, 100));
			functionalPanel.setVisible(false);
			frame1ContentPane.add(controlPanel, CC.xywh(5, 26, 80, 100));
			controlPanel.setVisible(true);

			frame1.pack();
			frame1.setLocationRelativeTo(frame1.getOwner());

			// frame1ContentPane.add(panel1, CC.xywh(5, 11, 145, 133));

		}
		// JFormDesigner - End of component initialization
		// //GEN-END:initComponents

		sourceInterfaceCombo.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {

				if (sourceInterfaceCombo.getSelectedItem() != null) {
					if (!sourceInterfaceCombo.getSelectedItem().equals(
							noneInterface)) {
						Iterator<Interface> it = allInterfaces.iterator();
						while (it.hasNext()) {
							Interface i = it.next();
							if (i == sourceInterfaceCombo.getSelectedItem())
								loadComponentTree(i);
						}
					} else {
						resetComponentTree();
					}
				}
			}
		});
	}

	private void createTransition() {
		if (transitionController.addTransition()) {
			this.frame1.setVisible(false);
		} else {
			showWrongTransitionNameDialog();
		}

	}

	private void cancelAction() {
		transitionController.cancelPendingTransitionAction();
		this.frame1.setVisible(false);
	}

	private void showWrongTransitionNameDialog() {
		if (transitionName.getText().equals("")) {
			JOptionPane.showMessageDialog(null,
					"A transition must have a name, please complete it.",
					"Invalid Transition Name", JOptionPane.QUESTION_MESSAGE);
		} else
			JOptionPane
					.showMessageDialog(
							null,
							this.transitionName.getText()
									+ " already exists as a transition name on this project, please change it.",
							"Invalid Transition Name",
							JOptionPane.QUESTION_MESSAGE);
	}

	@Override
	public void setController(TransitionController transitionController) {
		this.transitionController = transitionController;

	}

	@Override
	public void setTransitionName(String name) {
		this.transitionName.setText(name);
	}

	@Override
	public void showView() {
		if (this.operation == Operations.Updating) {
			cancelButton.setVisible(false);
			this.frame1.setTitle(UPDATE_TITLE);
		}
		frame1.pack();
		frame1.setVisible(true);
	}

	@Override
	public TransitionType getTransitionType() {
		return (TransitionType) this.transitionTypeComboBox
				.getItemAt(this.transitionTypeComboBox.getSelectedIndex());
	}

	@Override
	public void setModeUpdating() {
		this.frame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
	}

	@Override
	public String getTransitionName() {
		return this.transitionName.getText();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void setInterfaces(Iterable<Interface> allInterfaces) {

		this.allInterfaces = allInterfaces;

		Iterator<Interface> it = allInterfaces.iterator();
		while (it.hasNext()) {
			Interface i = it.next();
			sourceInterfaceCombo.addItem(i);
			destinationInterfaceCombo.addItem(i);
		}
	}

	private void loadComponentTree(Interface interf) {
		DefaultMutableTreeNode interfNode = new InterfaceTreeNode(interf);
		for (Object comp : interf.getComponents()) {
			if (((Component) comp).isComplex()) {
				ComplexComponent complex = (ComplexComponent) comp;
				ComponentTreeNode complexNode = new ComponentTreeNode(complex);
				for (Component subcomp : complex.getComponents()) {
					complexNode.add(new ComponentTreeNode(subcomp));
				}
				interfNode.add(complexNode);
			} else {
				interfNode.add(new ComponentTreeNode((Component) comp));
			}

			// cleanView();
			// generateComponentTree(components.getComponent(), newNode);
		}
		componentRoot = interfNode;
		interfaceTreeModel = new DefaultTreeModel(componentRoot);
		interfaceTree.setModel(interfaceTreeModel);
	}

	private void resetComponentTree() {

		componentRoot = new DefaultMutableTreeNode("Components");
		interfaceTreeModel = new DefaultTreeModel(componentRoot);
		interfaceTree.setModel(interfaceTreeModel);
	}

	@Override
	public Interface getSourceInterface() {
		if (sourceInterfaceCombo.getSelectedItem() instanceof Interface) {
			return (Interface) sourceInterfaceCombo.getSelectedItem();
		}
		return null;
	}

	@Override
	public Interface getDestinationInterface() {
		if (destinationInterfaceCombo.getSelectedItem() instanceof Interface) {
			return (Interface) destinationInterfaceCombo.getSelectedItem();
		}
		return null;
	}

	@Override
	public void setTransitionType(TransitionType type) {
		this.transitionTypeComboBox.setSelectedItem(type);
	}

	@Override
	public void setTransitionSourceInterface(Interface source) {
		this.sourceInterfaceCombo.setSelectedItem(source);
	}

	@Override
	public void setTransitionDestinationInterface(Interface destination) {
		this.destinationInterfaceCombo.setSelectedItem(destination);
	}

	@Override
	public void setTransitionTypeEnable(boolean b) {
		this.transitionTypeComboBox.setEnabled(false);
	}

	@Override
	public void setFunctionName(String functionName) {
		this.functionName.setText(functionName);
	}

	@Override
	public String getFunctionName() {
		return this.functionName.getText();
	}

	@Override
	public Component getComponentTrigger() {
		if (this.getTransitionType() == TransitionType.Control) {
			ComponentTreeNode node = null;
			if (interfaceTree.getLastSelectedPathComponent() instanceof ComponentTreeNode)
				node = (ComponentTreeNode) interfaceTree
						.getLastSelectedPathComponent();
			if (node != null)
				return node.getComponent();
		}
		return null;
	}

	@Override
	public void setComponentTrigger(Component componentTrigger) {
		// Searching the tree to match the trigger ID
		DefaultMutableTreeNode node = searchNode(componentTrigger.getId());

		if (node != null) {
			TreeNode[] nodes = interfaceTreeModel.getPathToRoot(node);
			TreePath path = new TreePath(nodes);
			interfaceTree.setSelectionPath(path);
		}

	}

	@SuppressWarnings("rawtypes")
	private DefaultMutableTreeNode searchNode(UUID compId) {
		DefaultMutableTreeNode node = null;
		Enumeration e = componentRoot.children();
		while (e.hasMoreElements()) {
			node = (DefaultMutableTreeNode) e.nextElement();
			if (((ComponentTreeNode) node).getComponent().getId() == compId) {
				return node;
			}
		}
		return null;
	}

	@Override
	public void setOperation(Operations operation) {
		this.operation = operation;
	}
}
